#include "latlondialog.h"
#include "ftpushbutton.h"
#include "ftlabel.h"
#include "ftlineedit.h"
#include "ftcheckbox.h"
#include "ftvboxlayout.h"
#include "ftradiobutton.h"
#include "fthboxlayout.h"

#include "ll-utm/LatLong-UTMconversion.h"


LatLonDialog::LatLonDialog(double lat,
                      double lon,
                      Configuration::coordinate_format df):
    RotatingDialog()
{
    activeFormat = df;
    latitude = lat;
    longitude = lon;

    buildTop();
    buildDec();
    buildDms();
    buildDm();
    buildUtm();

    doubleToData();
    if ( df == Configuration::degrees_minutes_seconds )
        formats->setCurrentWidget( dms );
    else if ( df == Configuration::decimal )
        formats->setCurrentWidget( dec );
    else if ( df == Configuration::degrees_minutes )
        formats->setCurrentWidget( dm );
    else if ( df == Configuration::utm )
        formats->setCurrentWidget( utm );
}

LatLonDialog::~LatLonDialog()
{
    foreach( QAbstractButton* btn, fbg.buttons() )
        fbg.removeButton( btn );

    foreach( QAbstractButton* btn, dec_ns.buttons() )
        dec_ns.removeButton( btn );

    foreach( QAbstractButton* btn, dec_ew.buttons() )
        dec_ew.removeButton( btn );

    foreach( QAbstractButton* btn, dms_ns.buttons() )
        dms_ns.removeButton( btn );

    foreach( QAbstractButton* btn, dms_ew.buttons() )
        dms_ew.removeButton( btn );

    foreach( QAbstractButton* btn, dm_ns.buttons() )
        dm_ns.removeButton( btn );

    foreach( QAbstractButton* btn, dm_ew.buttons() )
        dm_ew.removeButton( btn );
}

bool LatLonDialog::execLatLon(double& lat, double& lon)
{
    int ret = exec();
    dataToDouble();
    if ( ret == QDialog::Accepted )
    {
        lat = latitude;
        lon = longitude;
        return true;
    }
    return false;
}

void LatLonDialog::setDec()
{
    if ( activeFormat != Configuration::decimal )
    {
        dataToDouble();
        activeFormat = Configuration::decimal;
        doubleToData();
        formats->setCurrentWidget( dec );
    }
}

void LatLonDialog::setDms()
{
    if ( activeFormat != Configuration::degrees_minutes_seconds )
    {
        dataToDouble();
        activeFormat = Configuration::degrees_minutes_seconds;
        doubleToData();
        formats->setCurrentWidget( dms );
    }
}

void LatLonDialog::setDm()
{
    if ( activeFormat != Configuration::degrees_minutes)
    {
        dataToDouble();
        activeFormat = Configuration::degrees_minutes;
        doubleToData();
        formats->setCurrentWidget( dm );
    }
}

void LatLonDialog::setUtm()
{
    if ( activeFormat != Configuration::utm)
    {
        dataToDouble();
        activeFormat = Configuration::utm;
        doubleToData();
        formats->setCurrentWidget( utm );
    }
}
void LatLonDialog::buildTop()
{
    confirmButton = new FTPushButton( tr("Confirm") );
    connect( confirmButton, SIGNAL(clicked()),
             this, SLOT(accept()) );

    cancelButton = new FTPushButton( tr("Cancel") );
    connect( cancelButton, SIGNAL(clicked()),
             this, SLOT(reject()) );

    format_ddd_ddddddd = new FTRadioButton( tr("Use decimal degrees") );
    connect( format_ddd_ddddddd, SIGNAL(clicked()),
             this, SLOT(setDec()) );

    format_ddd_mm_ss = new FTRadioButton( tr("Use minutes and seconds" ) );
    connect( format_ddd_mm_ss, SIGNAL(clicked()),
             this, SLOT(setDms()) );

    format_ddd_mm = new FTRadioButton( tr("Use minutes") );
    connect( format_ddd_mm, SIGNAL(clicked()),
             this, SLOT(setDm()) );

    format_utm = new FTRadioButton( tr("Use UTM format" ) );
    connect( format_utm, SIGNAL(clicked()),
             this, SLOT(setUtm()) );

    fbg.addButton( format_ddd_ddddddd );
    fbg.addButton( format_ddd_mm_ss );
    fbg.addButton( format_ddd_mm );
    fbg.addButton( format_utm );

    if ( activeFormat == Configuration::decimal )
        format_ddd_ddddddd->setChecked( true );
    else if ( activeFormat == Configuration::degrees_minutes_seconds )
        format_ddd_mm_ss->setChecked( true );
    else if ( activeFormat == Configuration::degrees_minutes )
        format_ddd_mm->setChecked( true );
    else if ( activeFormat == Configuration::utm )
        format_utm->setChecked( true );

    formats = new QStackedWidget();
}

void LatLonDialog::buildDec()
{
    dec = new QWidget();
    formats->addWidget( dec );

    dec_latitudeLabel = new FTLabel( tr("Latitude (decimal degrees, no sign)"));
    dec_lat = new FTLineEdit("0.0");
    dec_lat->setInputMask("00.000000");
    dec_north = new FTCheckBox( tr("North") );
    dec_south = new FTCheckBox( tr("South") );
    dec_ns.addButton( dec_north );
    dec_ns.addButton( dec_south );

    dec_longitudeLabel = new FTLabel( tr("Longitude (decimal degrees, no sign)"));
    dec_lon = new FTLineEdit("0.0");
    dec_lon->setInputMask("000.000000");
    dec_east = new FTCheckBox( tr("East") );
    dec_west = new FTCheckBox( tr("West") );
    dec_ew.addButton( dec_east );
    dec_ew.addButton( dec_west );
}


void LatLonDialog::buildDms()
{
    dms = new QWidget();
    formats->addWidget( dms );

    dms_latitudeLabel = new FTLabel( tr("Latitude (degrees, minutes, seconds)"));
    dms_lat = new FTLineEdit( "0" );
    dms_lat->setMaxChars( 3 );
    dms_lat_minutes = new FTLineEdit( "0" );
    dms_lat_minutes->setMaxChars( 3 );
    dms_lat_seconds = new FTLineEdit( "0.0" );
    dms_lat_seconds->setMaxChars( 8 );
    dms_north = new FTCheckBox( tr("North") );
    dms_south = new FTCheckBox( tr("South") );
    dms_ns.addButton( dms_north );
    dms_ns.addButton( dms_south );

    dms_longitudeLabel = new FTLabel( tr("Longitude (degrees, minutes, seconds)"));
    dms_lon = new FTLineEdit( "0" );
    dms_lon->setMaxChars( 3 );
    dms_lon_minutes = new FTLineEdit( "0" );
    dms_lon_minutes->setMaxChars( 3 );
    dms_lon_seconds = new FTLineEdit( "0.0" );
    dms_lon_seconds->setMaxChars( 8 );
    dms_east = new FTCheckBox( tr("East") );
    dms_west = new FTCheckBox( tr("West") );
    dms_ew.addButton( dms_east );
    dms_ew.addButton( dms_west );
}

void LatLonDialog::buildDm()
{
    dm = new QWidget();
    formats->addWidget( dm );

    dm_latitudeLabel = new FTLabel( tr("Latitude (degrees, minutes)"));
    dm_lat = new FTLineEdit( "0" );
    dm_lat->setMaxChars( 4 );
    dm_lat_minutes = new FTLineEdit( "0.0" );
    dm_lat_minutes->setMaxChars( 8 );
    dm_north = new FTCheckBox( tr("North") );
    dm_south = new FTCheckBox( tr("South") );
    dm_ns.addButton( dm_north );
    dm_ns.addButton( dm_south );

    dm_longitudeLabel = new FTLabel( tr("Longitude (degrees, minutes)"));
    dm_lon = new FTLineEdit( "0" );
    dm_lon->setMaxChars( 4 );
    dm_lon_minutes = new FTLineEdit( "0.0" );
    dm_lon_minutes->setMaxChars( 8 );
    dm_east = new FTCheckBox( tr("East") );
    dm_west = new FTCheckBox( tr("West") );
    dm_ew.addButton( dm_east );
    dm_ew.addButton( dm_west );
}

void LatLonDialog::buildUtm()
{
    utm = new QWidget();
    formats->addWidget( utm );

    utm_northingLabel = new FTLabel( tr("UTM Northing:"));
    utm_northing = new FTLineEdit( "0.0" );

    utm_eastingLabel = new FTLabel( tr("UTM Easting:"));
    utm_easting = new FTLineEdit( "0.0" );

    utm_zoneLabel = new FTLabel( tr("UTM Zone:"));
    utm_zone = new FTLineEdit( "0.0" );
}

void LatLonDialog::dataToDouble()
{
    if ( activeFormat == Configuration::decimal )
    {
        latitude = dec_lat->text().toDouble();
        if ( dec_south->isChecked() )
            latitude *= -1;
        longitude = dec_lon->text().toDouble();
        if ( dec_west->isChecked() )
            longitude *= -1;
    }
    else if ( activeFormat == Configuration::degrees_minutes_seconds )
    {
        double minutes;
        double seconds;

        seconds = dms_lat_seconds->text().toDouble();
        seconds = seconds / 3600.0;
        minutes = dms_lat_minutes->text().toDouble();
        minutes = minutes / 60.0;
        latitude = dms_lat->text().toDouble() + minutes + seconds;
        if ( dms_south->isChecked() )
            latitude *= -1;
        seconds = dms_lon_seconds->text().toDouble();
        seconds = seconds / 3600.0;
        minutes = dms_lon_minutes->text().toDouble();
        minutes = minutes / 60.0;
        longitude = dms_lon->text().toDouble() + minutes + seconds;
        if ( dms_west->isChecked() )
            longitude *= -1;
    }
    else if ( activeFormat == Configuration::degrees_minutes )
    {
        double minutes;

        minutes = dm_lat_minutes->text().toDouble();
        minutes = minutes / 60.0;
        latitude = dm_lat->text().toDouble() + minutes;
        if ( dm_south->isChecked() )
            latitude *= -1;
        minutes = dm_lon_minutes->text().toDouble();
        minutes = minutes / 60.0;
        longitude = dm_lon->text().toDouble() + minutes;
        if ( dm_west->isChecked() )
            longitude *= -1;
    }
    else if ( activeFormat == Configuration::utm )
    {
        double easting = utm_easting->text().toDouble();
        double northing = utm_northing->text().toDouble();
        UTMtoLL( 23, northing,
                     easting,
                     utm_zone->text().toAscii(),
                     latitude,longitude);
    }

}

void LatLonDialog::doubleToData()
{
    if ( activeFormat == Configuration::decimal )
    {
        dec_lat->setText( QString("%1").arg(fabs( latitude ), 0, 'f') );
        if ( latitude >= 0 )
            dec_north->setChecked( true );
        else
            dec_south->setChecked( true );

        dec_lon->setText( QString("%1").arg(fabs( longitude ), 0, 'f') );
        if ( longitude >= 0 )
            dec_east->setChecked( true );
        else
            dec_west->setChecked( true );
    }
    else if ( activeFormat == Configuration::degrees_minutes_seconds )
    {
        int deg = (int)latitude;
        double tmp = (latitude - (double)deg) * 60.0;
        int min = (int)tmp;
        double sec = (int)((tmp - (double)min) * 60.0);
        dms_lat->setText( QString("%1").arg( abs(deg) ) );
        dms_lat_minutes->setText( QString("%1").arg( abs(min) ) );
        dms_lat_seconds->setText( QString("%1").arg( fabs(sec), 0, 'f' ) );

        deg = (int)longitude;
        tmp = (longitude - (double)deg) * 60.0;
        min = (int)tmp;
        sec = (int)((tmp - (double)min) * 60.0);
        dms_lon->setText( QString("%1").arg( abs(deg) ) );
        dms_lon_minutes->setText( QString("%1").arg( abs(min) ) );
        dms_lon_seconds->setText( QString("%1").arg( fabs(sec), 0, 'f' ) );

        if ( longitude >= 0 )
            dms_east->setChecked( true );
        else
            dms_west->setChecked( true );

        if ( latitude >= 0 )
            dms_north->setChecked( true );
        else
            dms_south->setChecked( true );
    }
    else if ( activeFormat == Configuration::degrees_minutes )
    {
        int deg = (int)latitude;
        double min = (latitude - (double)deg) * 60.0;
        dm_lat->setText( QString("%1").arg(abs(deg)) );
        dm_lat_minutes->setText( QString("%1").arg( fabs(min), 0, 'f' ) );

        deg = (int)longitude;
        min = (longitude - (double)deg) * 60.0;
        dm_lon->setText( QString("%1").arg( abs(deg) ) );
        dm_lon_minutes->setText( QString("%1").arg( fabs(min), 0, 'f' ) );

        if ( longitude >= 0 )
            dm_east->setChecked( true );
        else
            dm_west->setChecked( true );

        if ( latitude >= 0 )
            dm_north->setChecked( true );
        else
            dm_south->setChecked( true );
    }
    else if ( activeFormat == Configuration::utm )
    {
        double utmN, utmE;
        char utmZc[20];
        LLtoUTM( 23, latitude, longitude, utmN, utmE, utmZc);
        utm_easting->setText( QString("%1").arg( utmE, 0, 'f' ) );
        utm_northing->setText( QString("%1").arg( utmN, 0, 'f' ) );
        utm_zone->setText( utmZc );
    }
}


QLayout* LatLonDialog::createVertical()
{
    FTVBoxLayout* grid;
    FTVBoxLayout* nsew;
    FTHBoxLayout* hgrid;

    if ( dec->layout() != NULL )
        delete dec->layout();
    grid = new FTVBoxLayout();
    grid->addWidget( dec_latitudeLabel );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( dec_lat );
    nsew = new FTVBoxLayout();
    nsew->addWidget( dec_north );
    nsew->addWidget( dec_south );
    hgrid->addLayout( nsew );
    grid->addLayout( hgrid );
    grid->addWidget( dec_longitudeLabel );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( dec_lon );
    nsew = new FTVBoxLayout();
    nsew->addWidget( dec_west );
    nsew->addWidget( dec_east );
    hgrid->addLayout( nsew );
    grid->addLayout( hgrid );
    dec->setLayout( grid );

    if ( dms->layout() != NULL )
        delete dms->layout();
    grid = new FTVBoxLayout();
    grid->addWidget( dms_latitudeLabel );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( dms_lat );
    hgrid->addWidget( dms_lat_minutes );
    hgrid->addWidget( dms_lat_seconds );
    nsew = new FTVBoxLayout();
    nsew->addWidget( dms_north );
    nsew->addWidget( dms_south );
    hgrid->addLayout( nsew );
    grid->addLayout( hgrid );
    grid->addWidget( dms_longitudeLabel );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( dms_lon );
    hgrid->addWidget( dms_lon_minutes );
    hgrid->addWidget( dms_lon_seconds );
    nsew = new FTVBoxLayout();
    nsew->addWidget( dms_west );
    nsew->addWidget( dms_east );
    hgrid->addLayout( nsew );
    grid->addLayout( hgrid );
    dms->setLayout( grid );

    if ( dm->layout() != NULL )
        delete dm->layout();
    grid = new FTVBoxLayout();
    grid->addWidget( dm_latitudeLabel );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( dm_lat );
    hgrid->addWidget( dm_lat_minutes );
    nsew = new FTVBoxLayout();
    nsew->addWidget( dm_north );
    nsew->addWidget( dm_south );
    hgrid->addLayout( nsew );
    grid->addLayout( hgrid );
    grid->addWidget( dm_longitudeLabel );
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( dm_lon );
    hgrid->addWidget( dm_lon_minutes );
    nsew = new FTVBoxLayout();
    nsew->addWidget( dm_west );
    nsew->addWidget( dm_east );
    hgrid->addLayout( nsew );
    grid->addLayout( hgrid );
    dm->setLayout( grid );

    if ( utm->layout() != NULL )
        delete utm->layout();
    grid = new FTVBoxLayout();
    grid->addWidget( utm_northingLabel );
    grid->addWidget( utm_northing );
    grid->addWidget( utm_eastingLabel );
    grid->addWidget( utm_easting );
    grid->addWidget( utm_zoneLabel );
    grid->addWidget( utm_zone );
    utm->setLayout( grid );

    grid = new FTVBoxLayout();
    grid->addWidget( format_ddd_ddddddd );
    grid->addWidget( format_ddd_mm_ss );
    grid->addWidget( format_ddd_mm );
    grid->addWidget( format_utm );
    grid->addStretch();
    grid->addWidget( formats );
    grid->addStretch();
    hgrid = new FTHBoxLayout();
    hgrid->addWidget( confirmButton );
    hgrid->addWidget( cancelButton );
    grid->addLayout( hgrid );
    return grid;
}
